package com.proxyDemo;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @program: SpringBootDemos
 * @description:
 * @author: Kangsen
 * @create: 2022-09-13 11:50
 **/
public class LogProxy {

    /**
     * JDK Proxy 是 Java 语言自带的功能，无需通过加载第三方类实现；
     * Java 对 JDK Proxy 提供了稳定的支持，并且会持续的升级和更新，Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多；
     * JDK Proxy 是通过拦截器加反射的方式实现的；
     * JDK Proxy 只能代理实现接口的类；
     * JDK Proxy 实现和调用起来比较简单；
     * @param obj
     * @return
     */
    public static Object getObject(final Object obj){
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        long startTimeMillis = System.currentTimeMillis();
                        //执行方法的调用
                        Object invoke = method.invoke(obj, args);
                        //方法执行后
                        long endTimeMillis = System.currentTimeMillis();
                        //统计方法执行时间
                        System.out.println("执行耗时:" + (endTimeMillis-startTimeMillis) + " ms");
                        return invoke;
                    }
                });
    }

    /**
     * CGLib 是第三方提供的工具，基于 ASM 实现的，性能比较高；
     * CGLib 无需通过接口来实现，它是针对类实现代理，主要是对指定的类生成一个子类，它是通过实现子类的方式来完成调用的。
     */
    public static Object getObjectByCglib(final Object obj){
        Object proxyObj = Enhancer.create(obj.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                long timeMillis = System.currentTimeMillis();
                Object invoke = method.invoke(obj, objects);
                long endTime = System.currentTimeMillis();
                System.out.println("耗时 :" +(timeMillis - endTime)+"ms");
                return invoke;
            }
        });
        return proxyObj;
    }
}
